#pragma semicolon 1
#include <sourcemod>
#include <cstrike>
#include <ncs_rpg>

#define VERSION		"Beta 1.0.3"

new iMaxExp, iCreditsInc;
new iMSG_HurtXP, iMSG_KillXP, iMSG_WinXP, iStatsMenu, iStatsMenuTime;

new Float:fKnifeXP, Float:fDamageXP, Float:fArmorXP, Float:fTeamWinXP, Float:fKillXP, Float:fHeadShotXP;

new Float:fClientHurtXP[MAXPLAYERS+1], Float:fClientKnifeXP[MAXPLAYERS+1], Float:fClientArmorXP[MAXPLAYERS+1],
Float:fClientWinXP[MAXPLAYERS+1], Float:fClientHeadShotXP[MAXPLAYERS+1], Float:fClientKillXP[MAXPLAYERS+1];

new Handle:mp_round_restart_delay = INVALID_HANDLE;

public Plugin:myinfo =
{
	name		= "[NCS RPG] XP",
	author		= "[RUS] DiviX",
	description	= "XP system for NCS RPG",
	version		= VERSION,
	url			= "N/A"
};

public OnPluginStart()
{
	LoadTranslations("ncs_rpg/ncs_rpg.xp.phrases");
	
	mp_round_restart_delay = FindConVar("mp_round_restart_delay");
	if(mp_round_restart_delay == INVALID_HANDLE)
		LogError("Could not find a cvar 'mp_round_restart_delay'");
	
	iMaxExp = GetConfigValue("xp", "max_exp", 5000);
	iCreditsInc = GetConfigValue("xp", "credits_inc", 5);
	
	fKnifeXP = GetConfigValueFloat("xp", "knife", 10.0)*0.01;
	fDamageXP = GetConfigValueFloat("xp", "dmg", 25.0)*0.01;
	fArmorXP = GetConfigValueFloat("xp", "dmg_armor", 25.0)*0.01;
	fTeamWinXP = GetConfigValueFloat("xp", "team_win", 20.0);
	fKillXP = GetConfigValueFloat("xp", "exp", 25.0);
	fHeadShotXP = GetConfigValueFloat("xp", "headshot", 100.0);
	
	iMSG_HurtXP = GetConfigValue("advert", "xp_hurt", 1);
	iMSG_KillXP = GetConfigValue("advert", "xp_kill", 1);
	iMSG_WinXP = GetConfigValue("advert", "xp_win", 0);
	iStatsMenu = GetConfigValue("advert", "xp_menu", 1);
	iStatsMenuTime = GetConfigValue("advert", "xp_menu_time", -1);
	
	//HookEvent("player_team", Event_PlayerTeam);
	//HookEvent("round_start", Event_RoundStart);
	HookEvent("round_end", Event_RoundEnd);
	HookEvent("player_spawn", Event_PlayerSpawn, EventHookMode_Pre);
	HookEvent("player_hurt", Event_PlayerHurt, EventHookMode_Pre);
	HookEvent("player_death", Event_PlayerDeath);
}

public OnClientConnected(client)
{
	ResetXP(client);
}

public Event_PlayerSpawn(Handle:event, const String:name[], bool:dontBroadcast)
{
	new client = GetClientOfUserId(GetEventInt(event, "userid"));
	//if(IsValidPlayer(client))
	ResetXP(client);
}

public Event_RoundEnd(Handle:event, const String:name[], bool:dontBroadcast)
{
	new winner = GetEventInt(event, "winner");
	for(new client = 1; client <= MaxClients; client++)
	{
		if(!IsValidPlayer(client))
			continue;
		
		if(!IsPlayerAlive(client))
			continue;
		
		if(GetClientTeam(client) == winner)
		{
			new xp = RoundToNearest(GetTeamRatio(client)*fTeamWinXP);
			CheckMaxXP(xp);
			fClientWinXP[client] += xp;
			LevelUP(client, xp, iMSG_WinXP?true:false);
		}
		GivePlayerXP(client);
	}
}

public Event_PlayerHurt(Handle:event, const String:name[], bool:dontBroadcast)
{
	new victim = GetClientOfUserId(GetEventInt(event, "userid"));
	new attacker = GetClientOfUserId(GetEventInt(event, "attacker"));
	if(IsValidPlayer(victim) && IsValidPlayer(attacker) && victim != attacker)
	{
		new Float:knife = 0.0, Float:dmg_health = 0.0;
		dmg_health = GetEventFloat(event, "dmg_health");
		if(IsActiveWeaponKnife(attacker))
		{
			knife = dmg_health*fKnifeXP;
			fClientKnifeXP[attacker] += knife;
		}
		if(GetClientHealth(victim) < 0)
			dmg_health += float(GetClientHealth(victim));
		
		dmg_health *= fDamageXP;
		dmg_health += knife;
		
		new Float:dmg_armor = 0.0;
		if(fArmorXP)
		{
			dmg_armor = GetEventFloat(event, "dmg_armor");
			if(GetClientArmor(victim) < 0)
				dmg_armor += float(GetClientArmor(victim));
			dmg_armor *= fArmorXP;
			fClientArmorXP[attacker] += dmg_armor;
		}
		fClientHurtXP[attacker] += dmg_health+dmg_armor;
	}
}

public Event_PlayerDeath(Handle:event, const String:name[], bool:dontBroadcast)
{
	new victim = GetClientOfUserId(GetEventInt(event, "userid"));
	new attacker = GetClientOfUserId(GetEventInt(event, "attacker"));
	if(IsValidPlayer(victim))
	{
		GivePlayerXP(victim);
		
		if(IsValidPlayer(attacker) && victim != attacker)
		{
			new bool:headshot = GetEventBool(event, "headshot");
			new xp = RoundToNearest(float(GetLevel(victim))*fKillXP/float(GetLevel(attacker)));
			CheckMaxXP(xp);
			fClientKillXP[attacker] += xp;
			if(headshot)
			{
				xp += RoundToNearest(fHeadShotXP);
				fClientHeadShotXP[attacker] += fHeadShotXP;
			}
			LevelUP(attacker, xp, iMSG_KillXP?true:false);
		}
	}
}

CheckMaxXP(xp)
{
	if(iMaxExp > 0 && xp > iMaxExp)
		xp = iMaxExp;
}

LevelUP(client, xp, bool:msg = true)
{
	new level = 0;
//	if(iMaxExp > 0 && xp > iMaxExp)
//		xp = iMaxExp;
	
	new exp = xp+GetXP(client);
	
	while(exp >= GetReqXP(client))
	{
		exp -= GetReqXP(client);
		SetLevel(client, GetLevel(client)+1);
		level++;
	}
	
	SetXP(client, exp);
	if(msg && xp > 0)
		CPrintToChat(client, CPrefix, "You got XP FULL", client, xp, GetXP(client), GetReqXP(client));
	
	if(level > 0)
	{
		exp = level*iCreditsInc;
		SetCredits(client, GetCredits(client)+exp);
		if(msg)
		{
			CPrintToChat(client, CPrefix, "Level UP FULL", client, level, GetLevel(client));
			CPrintToChat(client, CPrefix, "You got credits FULL", client, exp, GetCredits(client));
		}
	}
}

GivePlayerXP(client)
{
	if(iStatsMenu)
	{
		new time;
		if(iStatsMenuTime < 0 && mp_round_restart_delay != INVALID_HANDLE)
			time = GetConVarInt(mp_round_restart_delay);
		else if(iStatsMenuTime > 0)
			time = iStatsMenuTime;
		else
			time = MENU_TIME_FOREVER;
		
		DisplayMenu(BuildMenuStats(client), client, time);
	}
		
	new xp = RoundToNearest(fClientHurtXP[client]);
	//CheckMaxXP(xp);
	ResetXP(client);
	if(xp > 0)
	{
		if(iMSG_HurtXP)
			CPrintToChat(client, CPrefix, "Hurt XP", client, xp);
		LevelUP(client, xp, iMSG_HurtXP?true:false);
	}
}

ResetXP(client)
{
	fClientHurtXP[client]		= 0.0;
	fClientKnifeXP[client]		= 0.0;
	fClientArmorXP[client]		= 0.0;
	fClientWinXP[client]		= 0.0;
	fClientHeadShotXP[client]	= 0.0;
	fClientKillXP[client]		= 0.0;
}

Float:GetTeamRatio(client)
{
	new team = GetClientTeam(client);
	if(team == CS_TEAM_SPECTATOR || team == CS_TEAM_NONE)
		return 0.0;
	
	new c1 = 0, c2 = 0;
	for(new i = 1; i <= MaxClients; i++)
	{
		if(IsValidPlayer(i))
		{
			if(GetClientTeam(i) == team)
				c1++;
			else
				c2++;
		}
	}
	if(c1 == 0 || c2 == 0)
		return 0.0;
	
	return float(c2)/float(c1);
}

stock bool:IsActiveWeaponKnife(client)
{
	new weapon = GetEntPropEnt(client, Prop_Data, "m_hActiveWeapon");
	if(weapon != -1)
	{
		decl String:buffer[32];
		GetEntPropString(weapon, Prop_Data, "m_iClassname", buffer, sizeof(buffer));
		if(StrEqual(buffer, "weapon_knife"))
			return true;
	}
	
	return false;
}

stock Handle:BuildMenuStats(client)
{
	new Handle:menu = CreateMenu(HandlerMenuStats);
	SetMenuTitle(menu, "%T", "Stats title", client, fClientKillXP[client], fClientHurtXP[client], fClientArmorXP[client], fClientKnifeXP[client], fClientHeadShotXP[client], fClientWinXP[client]);
	
	AddMenuItem(menu, " ", " ", ITEMDRAW_SPACER);
	
	return menu;
}


public HandlerMenuStats(Handle:menu, MenuAction:action, client, param2)
{
	if(action == MenuAction_End)
		CloseHandle(menu);
}